#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "account.h"
#include "ah_protocol.h"

#include "GeneralHashFunctions.h"


typedef unsigned int hash_function(char *key, unsigned int len);

hash_function *hash_func[11]={RSHash, JSHash, PJWHash, ELFHash, BKDRHash, SDBMHash, DJBHash, DEKHash, BPHash, FNVHash, APHash};
#define HASH_METHOD (1)
#define AH_HASHTABLE_SIZE (200)
static unsigned int ah_hash_table[AH_HASHTABLE_SIZE];
// Create account from Amber
struct account *new_account()
{
	struct account *acct = NULL;
	acct = (struct account *)getMempoolSet(sizeof(struct account));
	return acct;
}
void delete_account(struct account *acct)
{
	if(acct)
		retMempoolSet(acct,sizeof(struct account));
}
unsigned int ah_hash(char *key)
{
	unsigned int id;
	id = hash_func[HASH_METHOD](key, strlen(key));
	return id;
}
void init_hash_table()
{
	memset(ah_hash_table, 0 , sizeof(ah_hash_table));
}
int insert_HashTable(unsigned int hash_id)
{
	int hash_t = hash_id % AH_HASHTABLE_SIZE;
	int overflow_flag = hash_t;
	while(1)
	{
		if(ah_hash_table[hash_t]==0)
		{
			ah_hash_table[hash_t] = hash_id;
			printf("put id:%u into %d\n", hash_id, hash_t);
			return 1;
		}
		else
		{
			// collision
			printf("Hash table collision at %d\n", hash_t);
		}
		hash_t = (hash_t + 1) % AH_HASHTABLE_SIZE;
		if(overflow_flag == hash_t)
		{
			return 0;
		}
	}
}
unsigned int get_version()
{
	return 1;
}
unsigned int get_acct_type()
{
	return ACCT_PLAYER;
}
unsigned int get_acct_level()
{
	return 1;
}
struct acct_time get_total_time_played()
{
	struct acct_time ret;
	memset(&ret, 0 , sizeof(ret));
	return ret;
}
struct account_info *set_account_info(unsigned int version, unsigned int acct_type, char *name, char *passwd, unsigned int level, struct acct_time time_played)
{
	struct account_info *acct_info;
//	acct_info = (struct account_info *)malloc(sizeof(struct account_info));
	acct_info = (struct account_info *)getMempoolSet(sizeof(struct account_info));
	if(acct_info)
	{
		acct_info->ver = version;
		acct_info->acct_type = acct_type;
		acct_info->name = name;
		acct_info->passwd = passwd;
		acct_info->level = level;
		acct_info->time_played = time_played;
	}
	return acct_info;
}
void delete_account_info(struct account_info *acct_info)
{
	if(acct_info)
		retMempoolSet(acct_info,sizeof(struct account_info));
}
int write_acct_to_disk(struct account *acct)
{
	if(acct)
	{
		printf("=== ACCOUNT INFO ===\n");
		printf(" 0. id = %u\n", acct->id);
		printf(" 1. ver = %u\n", acct->acct_info->ver);
		printf(" 2. type = %u\n", acct->acct_info->acct_type);
		printf(" 3. name = %s\n", acct->acct_info->name);
		printf(" 4. passwd = %s\n", acct->acct_info->passwd);
		printf(" 5. level = %u\n", acct->acct_info->level);
		return 1;
	}
	return 0;
}
void create_account(unsigned int id, unsigned int version, struct account_info *info)
{
	struct account *acct = new_account();
	acct->id = id;
	acct->version = version;
	acct->acct_info = info;
	if(!write_acct_to_disk(acct))
		fprintf(stderr, "Write account to disk error!\n");
	delete_account_info(acct->acct_info);
	delete_account(acct);
}
int AH_create_account(char *acct_name , char *passwd)
{
	// Hash a ID
	unsigned int hash_id = ah_hash(acct_name);
	// Check if the ID is in hash table, if false, means collision! 
	if( insert_HashTable(hash_id) )
	{
		// Create the account!
		unsigned int version = get_version();
		unsigned int acct_type = get_acct_type();
		unsigned int level = get_acct_level();
		struct acct_time time_played = get_total_time_played();
		struct account_info *info = set_account_info(version, acct_type, acct_name, passwd, level, time_played);
	
		create_account(hash_id , version, info);
	
		return HA_CREATE_SUCCESS; 
	}
	// collision
	return HA_CREATE_FAILED;
}
